package com.example.drive.net.callback

import android.util.Log
import okhttp3.Response
import java.io.*

/**
 * 下载文件
 */
abstract class FileCallback(private val fileDir: String, private val fileName: String) :
    NetworkCallback<File> {
    companion object {
        private const val TAG: String = "FileCallback"
        private const val SIZE: Int = 1 shl 10
    }

    override fun parseNetworkResponse(response: Response): File? {
        return kotlin.runCatching {
            saveFile(response.body.byteStream(), fileDir, fileName)
        }.getOrElse {
            Log.e(TAG, "parseNetworkResponse error:$it")
            null
        }
    }

    /**
     * 保存文件
     *
     * @param inputStream 文件输入流
     * @param destFileDir 文件保存路径
     * @param destFileName 文件的名称
     * @return 保存好的文件
     */
    private fun saveFile(
        inputStream: InputStream,
        destFileDir: String,
        destFileName: String
    ): File? {
        var fos: FileOutputStream? = null
        var bos: BufferedOutputStream? = null
        var file: File? = null
        try {
            val dir = File(destFileDir)
            if (!dir.exists()) {
                dir.mkdirs()
            }
            file = File(destFileDir, destFileName)
            fos = FileOutputStream(file)
            bos = BufferedOutputStream(fos)
            val bytes = ByteArray(SIZE)
            var len: Int
            while (inputStream.read(bytes).apply { len = this } != -1) {
                bos.write(bytes, 0, len)
                bos.flush()
            }
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            close(bos)
            close(fos)
            close(inputStream)
        }
        return file
    }

    /**
     * 保存文件
     *
     * @param bytes 文件字节数组
     * @param destFileDir 文件保存路径
     * @param destFileName 文件的名称
     * @return 保存好的文件
     */
    private fun saveFile(bytes: ByteArray, destFileDir: String, destFileName: String): File? {
        var fos: FileOutputStream? = null
        var bos: BufferedOutputStream? = null
        var file: File? = null
        try {
            val dir = File(destFileDir)
            if (!dir.exists()) {
                dir.mkdirs()
            }
            file = File(destFileDir, destFileName)
            fos = FileOutputStream(file)
            bos = BufferedOutputStream(fos)
            bos.write(bytes)
            bos.flush()
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            close(bos)
            close(fos)
        }
        return file
    }

    private fun <T : Closeable> close(stream: T?) {
        try {
            stream?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}